package cn.iocoder.yudao.module.pi.controller.admin.pipline.exec;

import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.pi.controller.admin.pipline.deploy.vo.DeployBaseVO;
import cn.iocoder.yudao.module.pi.controller.admin.pipline.deploy.vo.DeployCreateReqVO;
import cn.iocoder.yudao.module.pi.controller.admin.pipline.exec.vo.*;
import cn.iocoder.yudao.module.pi.dal.dataobject.deploy.DeployDO;
import cn.iocoder.yudao.module.pi.dal.dataobject.exec.ExecDO;
import cn.iocoder.yudao.module.pi.dal.dataobject.task.TaskDO;
import cn.iocoder.yudao.module.pi.framework.config.JingJiShangIAMPoperties;
import cn.iocoder.yudao.module.pi.framework.config.YunShangIAMPoperties;
import cn.iocoder.yudao.module.pi.service.deploy.DeployService;
import cn.iocoder.yudao.module.pi.service.exec.ExecService;
import cn.iocoder.yudao.module.pi.service.task.TaskService;
import com.alibaba.fastjson.JSON;
import com.huaweicloud.sdk.codeartspipeline.v2.CodeArtsPipelineClient;
import com.huaweicloud.sdk.codeartspipeline.v2.model.*;
import com.huaweicloud.sdk.codeartspipeline.v2.region.CodeArtsPipelineRegion;
import com.huaweicloud.sdk.core.auth.BasicCredentials;
import com.huaweicloud.sdk.core.auth.ICredential;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.validation.Valid;
import java.util.*;

import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - 流水线部署执行")
@RestController
@RequestMapping("/pi/pipline/exec")
@Slf4j
public class PiplineExecController {
    @Resource
    private YunShangIAMPoperties yunShangIAMPoperties;
    @Resource
    private JingJiShangIAMPoperties jingJiShangIAMPoperties;
    @Resource
    private ExecService execService;
    @Resource
    private DeployService deployService;
    @Resource
    private TaskService taskService;

    @PostMapping("/create")
    @Operation(summary = "创建部署执行")
    //@PreAuthorize("@ss.hasPermission('pi:exec:create')")
    @PermitAll
    @TenantIgnore
    public CommonResult<ExecCreateRespVO> createExec(@Valid @RequestBody ExecCreateReqVO createReqVO) {
        ExecCreateRespVO execCreateRespVO = new ExecCreateRespVO();
        execCreateRespVO.setRunIds(new ArrayList<String>());
        DeployDO deploy = deployService.getDeploy(createReqVO.getDeployId());
        String batchId = UUID.randomUUID().toString();
        //每个env都需要发包
        createReqVO.getEnvs().forEach(env -> {
            exec(batchId, deploy, env, execCreateRespVO);
        });
        return success(execCreateRespVO);
    }

    private void exec(String batchId, DeployDO deploy, String env, ExecCreateRespVO execCreateRespVO) throws ServiceException {
        //获得流水线任务列表
        List<TaskDO> taskList = taskService.getTaskList(env, deploy.getDeployType());
        if (taskList.size() == 0) {
            throw new ServiceException(500, "没有可用的流水线任务");
        }
        TaskDO taskDO = taskList.get(0);
        Map<String, TaskDO> taskMap = new HashMap<>();
        taskList.forEach(task -> {
            taskMap.put(task.getTaskCiName(), task);
        });
        // The AK and SK used for authentication are hard-coded or stored in plaintext, which has great security risks. It is recommended that the AK and SK be stored in ciphertext in configuration files or environment variables and decrypted during use to ensure security.
        // In this example, AK and SK are stored in environment variables for authentication. Before running this example, set environment variables CLOUD_SDK_AK and CLOUD_SDK_SK in the local environment

        String ak = "";
        if (taskDO.getDeployType().startsWith("yunshang")) {
            ak = yunShangIAMPoperties.getAk();
        } else {
            ak = jingJiShangIAMPoperties.getAk();
        }
        String sk = "";
        if (taskDO.getDeployType().startsWith("yunshang")) {
            sk = yunShangIAMPoperties.getSk();
        } else {
            sk = jingJiShangIAMPoperties.getSk();
        }
        ICredential auth = new BasicCredentials()
                .withAk(ak)
                .withSk(sk);
        //设置region
        CodeArtsPipelineClient client = CodeArtsPipelineClient.newBuilder()
                .withCredential(auth)
                .withRegion(CodeArtsPipelineRegion.valueOf(taskDO.getRegion()))
                .build();
        RunPipelineRequest request = new RunPipelineRequest();
        //设置项目id
        request.withProjectId(taskDO.getProjectId());
        //设置流水线id
        request.withPipelineId(taskDO.getPiplineId());
        //设置sources
        List<RunPipelineDTOSources> listbodySources = new ArrayList<>();
        //获得tag列表
        List<DeployBaseVO.DataDTO> tagList = JSON.parseArray(deploy.getData(), DeployBaseVO.DataDTO.class);
        List<String> chooseStages = new ArrayList<>();
        List<String> chooseJobs = new ArrayList<>();
        List<String> variableParams = new ArrayList<>();
        List<RunPipelineDTOVariables> listbodyVariables = new ArrayList<>();
        Map<String, String> requestData = new HashMap<>(32);
        tagList.forEach(tag -> {
            List<DeployCreateReqVO.DataDTO.ServicesDTO> services = tag.getServices();
            services.forEach(service -> {
                String serviceName = service.getName();
                //判断是否包含该服务，有些阶段可能没有此服务
                if (taskMap.containsKey(serviceName)) {
                    TaskDO task = taskMap.get(serviceName);
                    //设置阶段
                    if (!chooseStages.contains(task.getStageCiId())) {
                        chooseStages.add(task.getStageCiId());
                    }
                    //设置任务
                    if (!chooseJobs.contains(task.getTaskCiId())) {
                        chooseJobs.add(task.getTaskCiId());
                    }
                    //设置变量
                    if (!variableParams.contains(serviceName)) {
                        RunPipelineDTOVariables variables = new RunPipelineDTOVariables();
                        //特别要注意参数只能用 _ 连接，不能用 - 连接
                        variables.setName(serviceName.replace("-", "_"));
                        variables.setValue(tag.getTag());
                        listbodyVariables.add(variables);
                        variableParams.add(serviceName);
                        requestData.put(serviceName.replace("-", "_"), tag.getTag());
                    } else {
                        RunPipelineDTOVariables variables = listbodyVariables.get(variableParams.indexOf(serviceName));
                        variables.setValue(tag.getTag());
                        requestData.put(serviceName.replace("-", "_"), tag.getTag());
                    }
                }
            });
        });
        //云商sit环境飞书通知任务是必须要执行的
        if (taskDO.getDeployType().equals("yunshang_platform_backend") && env.equals("sit")) {
            //飞书通知任务
            if (!chooseJobs.contains("JOB_mizYS")) {
                chooseJobs.add("JOB_mizYS");
            }
            //飞书通知阶段
            if (!chooseStages.contains("17454571796116fd6a69f-839d-40b0-9b14-8f8740a12596")) {
                chooseStages.add("17454571796116fd6a69f-839d-40b0-9b14-8f8740a12596");
            }
        }
        if (taskDO.getDeployType().equals("yunshang_platform_front") && env.equals("sit")) {
            //飞书通知任务
            if (!chooseJobs.contains("JOB_ECdbP")) {
                chooseJobs.add("JOB_ECdbP");
            }
            //飞书通知阶段
            if (!chooseStages.contains("174547510956335171d7b-50d7-47e3-a3f3-c26bef08eab0")) {
                chooseStages.add("174547510956335171d7b-50d7-47e3-a3f3-c26bef08eab0");
            }
        }
        //设置调用参数
        RunPipelineDTO body = new RunPipelineDTO();
        body.withSources(listbodySources);
        body.withVariables(listbodyVariables);
        body.setDescription(deploy.getInfo());
        body.setChooseJobs(chooseJobs);
        body.setChooseStages(chooseStages);
        request.withBody(body);
        try {
            //调用流水线
            RunPipelineResponse response = client.runPipeline(request);
            log.info("{}", response);
            execCreateRespVO.getRunIds().add(response.getPipelineRunId());
            ExecSaveReqVO createReqVO = new ExecSaveReqVO();
            createReqVO.setEnv(env);
            createReqVO.setDeployId(deploy.getId());
            createReqVO.setPiplineRunId(response.getPipelineRunId());
            createReqVO.setPiplineId(taskDO.getPiplineId());
            createReqVO.setProjectId(taskDO.getProjectId());
            createReqVO.setRegion(taskDO.getRegion());
            createReqVO.setData(deploy.getData());
            createReqVO.setBatchId(batchId);
            createReqVO.setDeployType(taskDO.getDeployType());
            createReqVO.setRequestData(JSONUtil.toJsonStr(requestData));
            execService.createExec(createReqVO);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    @PostMapping("/getExecWithRunDetail")
    @Operation(summary = "获得部署执行")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    //@PreAuthorize("@ss.hasPermission('pi:exec:query')")
    @PermitAll
    @TenantIgnore
    public CommonResult<ExecWithRunDetailRespVO> getExecWithRunDetail(@RequestParam("id") Long id) {
        ExecDO exec = execService.getExec(id);
        ExecWithRunDetailRespVO execWithRunDetailRespVO = new ExecWithRunDetailRespVO();
        BeanUtils.copyProperties(exec, execWithRunDetailRespVO);
        // The AK and SK used for authentication are hard-coded or stored in plaintext, which has great security risks. It is recommended that the AK and SK be stored in ciphertext in configuration files or environment variables and decrypted during use to ensure security.
        // In this example, AK and SK are stored in environment variables for authentication. Before running this example, set environment variables CLOUD_SDK_AK and CLOUD_SDK_SK in the local environment
        String ak = "";
        if (exec.getDeployType().startsWith("yunshang")) {
            ak = yunShangIAMPoperties.getAk();
        } else {
            ak = jingJiShangIAMPoperties.getAk();
        }
        String sk = "";
        if (exec.getDeployType().startsWith("yunshang")) {
            sk = yunShangIAMPoperties.getSk();
        } else {
            sk = jingJiShangIAMPoperties.getSk();
        }
        ICredential auth = new BasicCredentials()
                .withAk(ak)
                .withSk(sk);
        CodeArtsPipelineClient client = CodeArtsPipelineClient.newBuilder()
                .withCredential(auth)
                .withRegion(CodeArtsPipelineRegion.valueOf(exec.getRegion()))
                .build();
        ShowPipelineRunDetailRequest request = new ShowPipelineRunDetailRequest();
        request.withProjectId(exec.getProjectId());
        request.withPipelineId(exec.getPiplineId());
        request.withPipelineRunId(exec.getPiplineRunId());
        try {
            ShowPipelineRunDetailResponse response = client.showPipelineRunDetail(request);
            log.info("{}", response);
            execWithRunDetailRespVO.setResponse(response);
        } catch (Exception e) {
            log.error(e.getMessage());
            return error(1, e.getMessage());
        }
        return success(execWithRunDetailRespVO);
    }

    @GetMapping("/page")
    @Operation(summary = "获得部署执行分页")
    //@PreAuthorize("@ss.hasPermission('pi:exec:query')")
    @PermitAll
    @TenantIgnore
    public CommonResult<PageResult<ExecRespVO>> getExecPage(@Valid ExecPageReqVO pageReqVO) {
        PageResult<ExecDO> pageResult = execService.getExecPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, ExecRespVO.class));
    }

}
